#include "geracodigo.h"

u4 realu4(u4 orig){
    u1 a1, a2, a3, a4;
    a1 = 0x000000FF & orig;
    a2 = (0x0000FF00 & orig) >> 8;
    a3 = (0x00FF0000 & orig) >> 16;
    a4 = (0xFF000000 & orig) >> 24;

    u4 retorno = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;

    return retorno;
}

u2 realu2(u2 orig){
    u1 a1, a2;
    a1 = 0x00FF & orig;
    a2 = (0xFF00 & orig) >> 8;
    return (a1 << 8) | a2;
}

main(){
    geracodigo(root, head);
    return 0;
}

void geracodigo(TreeNode *raiz, Symbol *head){
    FILE *fp;
    u1 u1aux;
    u2 u2aux;
    if( (fp = fopen("minha.class", "w+b")) == NULL){
        printf("Erro! Nao foi possivel abrir o arquivo!\n");
        exit(1);
    }
    u4 magic = realu4(0xCAFEBABE);
    getchar();
    fwrite(&magic, sizeof(u4), 1, fp);

    u2 minorVersion = realu2(0x2F);
    fwrite(&minorVersion, 1, sizeof(u2), fp);
    u2 majorVersion = realu2(0x2F);
    fwrite(&majorVersion, 1, sizeof(u2), fp);
    //TODO, contar o tamanho de head;
    u2 constantPoolCount = realu2(6);
    fwrite(&constantPoolCount, 1, sizeof(u2), fp);
    //Escrevendo 1 entrada, caminho pra string nda classe
    u1aux = 7;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2(2); // aponta pra utf8
    fwrite(&u2aux, 1, sizeof(u1), fp);
    //2 entrada, string da classe (utf8)
    char nomeClasse[] = "PascalPortal";
    u1aux = 1;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2((u2)strlen(nomeClasse));
    fwrite(&u2aux, 1, sizeof(u2), fp);
    fwrite(nomeClasse, 1, sizeof(char)*strlen(nomeClasse), fp);
    //3 entrada MethodRef main
    u1aux = 10;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2(2); // aponta pra utf8 da class
    fwrite(&u2aux, 1, sizeof(u1), fp);
    u2aux = realu2(4); // aponta pra name_and_type
    fwrite(&u2aux, 1, sizeof(u1), fp);
    //4 entrada name_and_type MAIN
    u1aux = 12;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2(5); // aponta pra utf8 do metodo (main)
    fwrite(&u2aux, 1, sizeof(u1), fp);
    u2aux = realu2(6); // aponta pro descritor (main)
    fwrite(&u2aux, 1, sizeof(u1), fp);
    //5 entrada, string do metodo main (utf8)
    char nomestring[] = "<main>";
    u1aux = 1;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2((u2)strlen(nomestring));
    fwrite(&u2aux, 1, sizeof(u2), fp);
    fwrite(nomestring, 1, sizeof(char)*strlen(nomestring), fp);
    //6 entrada, string do descritor do metodo main (utf8)
    char nomestring2[] = "([Ljava/lang/String;)V";
    u1aux = 1;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2((u2)strlen(nomestring2));
    fwrite(&u2aux, 1, sizeof(u2), fp);
    fwrite(nomestring2, 1, sizeof(char)*strlen(nomestring2), fp);
    //7 entrada, string code (utf8)
    char nomestring3[] = "code";
    u1aux = 1;
    fwrite(&u1aux, 1, sizeof(u1), fp);
    u2aux = realu2((u2)strlen(nomestring3));
    fwrite(&u2aux, 1, sizeof(u2), fp);
    fwrite(nomestring3, 1, sizeof(char)*strlen(nomestring3), fp);

    //(Fim da pool) Continuando...
    u2 acessFlags = realu2(0x0001);
    fwrite(&acessFlags, 1, sizeof(u2), fp);
    u2 thisClass = realu2(1);
    fwrite(&thisClass, 1, sizeof(u2), fp);
    u2 superClass = 0;
    fwrite(&superClass, 1, sizeof(u2), fp);
    u2 interfacesCount = 0;
    fwrite(&interfacesCount, 1, sizeof(u2), fp);
    u2 fieldsCount = 0;
    fwrite(&fieldsCount, 1, sizeof(u2), fp);
    u2 methodsCount = 1;
    //Metodo Main
    u2 M_accesflags = realu2(0x0001);
    fwrite(&M_accesflags, 1, sizeof(u2), fp);
    u2 M_name_index = realu2(5);
    fwrite(&M_name_index, 1, sizeof(u2), fp);
    u2 M_descriptor_index = realu2(6);
    fwrite(&M_descriptor_index, 1, sizeof(u2), fp);
    u2 M_atrbutescount = realu2(1);
    fwrite(&M_atrbutescount, 1, sizeof(u2), fp);
    //atributo codigo
    u2 C_name_index = realu2(7);
    fwrite(&C_name_index, 1, sizeof(u2), fp);
    u2 C_sttribute_lenght = realu2(13);
    u2 C_max_stancks = realu2(10);
    u2 C_max_locals = realu2(10);
    u2 C_code_lenght = realu2(13);
/*
 0 iconst_0
 1 istore_1
 2 iconst_0
 3 istore_2
 4 iconst_0
 5 istore_3
 6 iload_1
 7 iload_2
 8 isub
 9 bipush 6
11 iadd
12 istore_3
13 getstatic #16 <java/lang/System.out>
16 new #22 <java/lang/StringBuilder>
19 dup
20 ldc #24 <z = >
22 invokespecial #26 <java/lang/StringBuilder.<init>>
25 iload_3
26 invokevirtual #29 <java/lang/StringBuilder.append>
29 invokevirtual #33 <java/lang/StringBuilder.toString>
32 invokevirtual #37 <java/io/PrintStream.println>
35 return


    if( (fp = fopen("minha.class", "wb")) == NULL){
        printf("Erro! Nao foi possivel abrir o arquivo!\n");
        exit(1);
    }

    classe->magic = leru4(fp);
    if ( classe->magic != 0xcafebabe){
        printf("Erro! Assinatura nao identificada ( CAFEBABE )\n %x\n", classe->magic);
        exit(1);
    }
    classe->minorVersion = leru2(fp);
    classe->majorVersion = leru2(fp);
    classe->constantPoolCount = leru2(fp);
    classe->cps = GetConstantes(fp, classe->constantPoolCount);
    classe->acessFlags = leru2(fp);
    classe->thisClass  = leru2(fp);
    classe->superClass = leru2(fp);
    classe->interfacesCount = leru2(fp);
    classe->interfaces = (u2*)calloc(classe->interfacesCount, sizeof(u2));

    for (i = 0; i< classe->interfacesCount; i++ ){
        ((u2*)classe->interfaces)[i] = leru2(fp);
    }
    classe->fieldsCount = leru2(fp);
    classe->fields = GetFields(classe, fp, classe->fieldsCount);// Perguntar sobre a redundancia de argumentos
    classe->methodsCount = leru2(fp);
    classe->methods = GetMetodo(classe, fp, classe->methodsCount);// Peruntar sobre a redundancia de argumentos
    classe->attributesCount = leru2(fp);*/
    return;
}
